﻿#pragma once

#include "qt_renderer.h"

#include <QCoreApplication>
#include <QMouseEvent>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLWidget>

/**
 * 继承预定义的窗口.
 */
class MainOpenGLWidget : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
  public:
    explicit MainOpenGLWidget(QWidget *parent = nullptr);
    ~MainOpenGLWidget();

  protected:
    virtual void initializeGL() override;
    virtual void paintGL() override;
    virtual void wheelEvent(QWheelEvent *) override;
    virtual void mousePressEvent(QMouseEvent *) override;
    virtual void mouseReleaseEvent(QMouseEvent *) override;
    virtual void mouseMoveEvent(QMouseEvent *) override;
    virtual void keyPressEvent(QKeyEvent *) override;
    virtual void keyReleaseEvent(QKeyEvent *) override;
    virtual void resizeEvent(QResizeEvent *event) override;

  public:
    CAGD_FRIEND_RENDERER

    struct FrameData
    {
        unsigned int frameID;
        unsigned int textureID;
        unsigned int RBO;
    };

  protected:
    // 着色器操作
    void GenerateShader(int i, const char *vertexPath, const char *fragmentPath, const char *geometryPath = nullptr);
    void BindShader(int i);
    void DeleteShader(int i);

    // 顶点数组操作
    void GenerateArray(int i);
    void BindArray(int i);
    void BindInsArray(int i);
    void UnbindArray();
    void DeleteArray(int i);

    // uniform 缓冲操作，当有多个着色器具有相同 uniform 变量时使用
    void GenerateUBO(int i);
    void BindUBO(int i);
    void UnbindUBO();
    void DeleteUBO(int i);

    // 纹理操作
    void GenerateTexture(int i);
    void LoadTexture1D(CAGD::TEXTURE texture, float a = 1.0);
    void LoadTexture2D(const char *file);
    void LoadTexture2D(CAGD::TEXTURE texture, float a = 1.0);
    void LoadTextureCube(std::vector<const char *> files);
    void ActiveTexture(int i);
    void BindTexture1D(int i);
    void BindTexture2D(int i);
    void BindTextureCube(int i);
    void UnbindTexture();
    void DeleteTexture(int i);

    // 帧缓冲操作
    void GenerateFrame(int i, int w, int h);
    void BindFrame(int i);
    void UnbindFrame();
    void DeleteFrame(int i);

    // 获得当前着色器
    QOpenGLShaderProgram *GetShader();

  protected:
    std::map<int, unsigned int> m_VAOs;              // 顶点数组对象 ID
    std::map<int, unsigned int> m_VBOs;              // 顶点缓冲对象 ID
    std::map<int, unsigned int> m_EBOs;              // 索引缓冲对象 ID
    std::map<int, unsigned int> m_Inss;              // 实例缓冲对象 ID
    std::map<int, unsigned int> m_UBOs;              // uniform 缓冲对象 ID
    std::map<int, unsigned int> m_textures;          // 2D 纹理 ID
    std::map<int, FrameData> m_frames;               // 帧缓冲对象 ID
    std::map<int, QOpenGLShaderProgram *> m_shaders; // 保存着色器

    QOpenGLShaderProgram *m_shader; // 当前着色器
};